package cc.yaomm.common.basic.captcha.generator;

import cc.yaomm.common.basic.domain.KeyValue;
import cc.yaomm.common.basic.captcha.config.CaptchaProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * Created by XQL on 2020/5/14.
 */
@Slf4j
public class CaptchaGenerator {

    private String[] numbers = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
    private String[] uppers = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
    private String[] lowers = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
    private String chinese = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二" +
            "理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系" +
            "军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色" +
            "光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米" +
            "整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维" +
            "划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞";


    @Autowired
    CaptchaProperties captchaProperties;

    /**
     * <p>@Description : 验证码生成器</p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2020/5/14  </p>
     */
    public KeyValue<String, String> generate() {
        switch (captchaProperties.getType()) {
            case "arithmetic":
                return this.generateArithmetic();
            case "chinese":
                return this.generateChinese();
            default:
                return this.generateGeneral();
        }
    }

    /**
     * <p>@Description : 生成普通验证码</p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2020/5/28  </p>
     */
    public KeyValue<String, String> generateGeneral() {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        //定义候选池
        List<String> list = new ArrayList<>();
        if (captchaProperties.getNumber() == null) {
            list.addAll(Arrays.asList(numbers));
            if (captchaProperties.getUpper() == null) {
                list.addAll(Arrays.asList(uppers));
                list.addAll(Arrays.asList(lowers));
            } else if (captchaProperties.getUpper()) {
                list.addAll(Arrays.asList(uppers));
            } else {
                list.addAll(Arrays.asList(lowers));
            }
        } else if (captchaProperties.getNumber()) {
            list.addAll(Arrays.asList(numbers));
        } else {
            list.addAll(Arrays.asList(uppers));
            list.addAll(Arrays.asList(lowers));
        }

        //根据长度生成验证码
        for (int i = 0; i < captchaProperties.getLength(); i++) {
            sb.append(list.get(random.nextInt(list.size())));
        }
        log.info("验证码：{}", sb.toString());
        return new KeyValue<>(sb.toString(), sb.toString());
    }

    /**
     * <p>@Description : 生成算术验证码</p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2020/5/28  </p>
     */
    public KeyValue<String, String> generateArithmetic() {
        char[] symbols = new char[]{'+', '-', '×', '÷'};
        Random random = new Random();
        int[] values = new int[3];
        values[0] = random.nextInt(20);
        values[1] = random.nextInt(20);
        char symbol = symbols[random.nextInt(4)];
        switch (symbol) {
            case '+':
                values[2] = values[0] + values[1];
                break;
            case '-':
                if (values[0] > values[1]) {
                    values[2] = values[0] - values[1];
                } else {
                    values[2] = values[1] - values[0];
                }
                break;
            case '×':
                values[2] = values[0] * values[1];
                break;
            case '÷':
                values[2] = values[0];
                values[0] = values[2] * values[1];
                break;
        }

        int index = random.nextInt(3);
        StringBuffer captcha = new StringBuffer();
        for (int i = 0; i < values.length; i++) {
            if (i == index) {
                captcha.append("?");
            } else {
                captcha.append(values[i]);
            }
            if (i == 0) {
                captcha.append(symbol);
            }
            if (i == 1) {
                captcha.append("=");
            }
        }

        log.info("表达式：{}，验证码：{}", captcha.toString(), values[index]);
        return new KeyValue<>(captcha.toString(), String.valueOf(values[index]));
    }

    /**
     * <p>@Description : 中文验证码</p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2020/5/28  </p>
     */
    public KeyValue<String, String> generateChinese() {
        StringBuffer captcha = new StringBuffer();
        //随机数对象
        Random random = new Random();
        for (int i = 0; i < captchaProperties.getLength(); i++) {
//            // 第一种生成方式
//            ///区码，0xA0打头，从第16区开始，即0xB0=11*16=176,16~55一级汉字，56~87二级汉字
//            int highPos = (176 + Math.abs(random.nextInt(39)));
//            //位码，0xA0打头，范围第1~94列
//            int lowPos = (161 + Math.abs(random.nextInt(93)));
//            //字节码
//            byte[] b = new byte[2];
//            b[0] = (Integer.valueOf(highPos)).byteValue();
//            b[1] = (Integer.valueOf(lowPos)).byteValue();
//            try {
//                //区位码组合成汉字
//                captcha.append(new String(b, "GBK"));
//            } catch (UnsupportedEncodingException e) {
//                captcha.append("一");
//            }

            // 第二种生成方式 常用500字
            captcha.append(chinese.charAt(random.nextInt(chinese.length())));
        }
        log.info("验证码：{}", captcha.toString());
        return new KeyValue<>(captcha.toString(), captcha.toString());
    }

}
